package cn.flkj.lucia2a2.intermediate;

import org.hyperledger.fabric.sdk.*;
import org.hyperledger.fabric.sdk.exception.ChaincodeEndorsementPolicyParseException;
import org.hyperledger.fabric.sdk.exception.CryptoException;
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric.sdk.exception.ProposalException;
import org.hyperledger.fabric.sdk.security.CryptoSuite;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @author : 州长在手 2021/1/6 下午3:34
 */
public class IntermediateLifecycleChaincode {

    private String chaincodeName ;
    private String chaincodeVersion ;
    private String chaincodeLabel ;
    private String chaincodeSourceLocation ;
    private String chaincodePath ;
    private String metadadataSource ;
    private String chaincodeEndorsementPolicyPath;
    private ChaincodeCollectionConfiguration chaincodeCollectionConfiguration ;
    private LifecycleChaincodeEndorsementPolicy chaincodeEndorsementPolicy;
    /**
     * 安装链码产生的packageID
     */
    // fabcar01042_1:825b254fb7feb28ad19013ba8c610a90edfcd3e94d295596aea7ebaf1ed723ea
    private String packageID;

    public IntermediateLifecycleChaincode() {
        try {
            chaincodeName = "fabcar010701";
            chaincodeVersion = "1";
            chaincodeLabel = "fabcar010701_1";
            chaincodeSourceLocation = "/home/ct/go";
            chaincodePath = "github.com/hyperledger/fabric-samples/chaincode/fabcar/go";
            metadadataSource = "/home/ct/IdeaProjects/fabric-sdk-java/src/test/fixture/meta-infs/end2endit";
            chaincodeEndorsementPolicy =
                    LifecycleChaincodeEndorsementPolicy.fromSignaturePolicyYamlFile(
                            Paths.get("/home/ct/IdeaProjects/fabric-sdk-java/src/test/fixture/sdkintegration/chaincodeendorsementpolicy.yaml"));

        } catch (Exception ignore) {
        }

    }

    public IntermediateLifecycleChaincode(String chaincodeName,
                                          String chaincodeVersion,
                                          String packageID){
        this.chaincodeName = chaincodeName;
        this.chaincodeVersion = chaincodeVersion;
        this.packageID = packageID;
    }

    public IntermediateLifecycleChaincode(String chaincodeName,
                                          String chaincodeVersion,
                                          String chaincodeLabel, // 标签，是名字加版本号的结合
                                          String chaincodeSourceLocation, // GOPATH
                                          String chaincodePath, // 相对于GOPATH的路径
                                          String metadadataSource, // metadadataSource,一般是couchdb的连接方式JSON的路径
                                          String chaincodeEndorsementPolicyPath, // 策略文件
                                          ChaincodeCollectionConfiguration chaincodeCollectionConfiguration //字符串代码集合配置,可能是私有数据
    ) throws IOException, ChaincodeEndorsementPolicyParseException {
        this.chaincodeName = chaincodeName;
        this.chaincodeVersion = chaincodeVersion;
        this.chaincodeLabel = chaincodeLabel;
        this.chaincodeSourceLocation = chaincodeSourceLocation;
        this.chaincodePath = chaincodePath;
        this.metadadataSource = metadadataSource;
        this.chaincodeEndorsementPolicyPath = chaincodeEndorsementPolicyPath;
        this.chaincodeCollectionConfiguration = chaincodeCollectionConfiguration;
        chaincodeEndorsementPolicy = LifecycleChaincodeEndorsementPolicy.fromSignaturePolicyYamlFile(
                        Paths.get(this.chaincodeEndorsementPolicyPath));
    }
    /**
     * 安装智能合约,包含打包和上传到peer节点
     */

    public String install(IntermediateOrg org) throws ProposalException, InvalidArgumentException, IOException {
        Path metadataSourcePath = null;
        if (metadadataSource != null) {
            metadataSourcePath = Paths.get(metadadataSource);
        }
        LifecycleChaincodePackage lifecycleChaincodePackage = LifecycleChaincodePackage.fromSource(chaincodeLabel, Paths.get(chaincodeSourceLocation),
                TransactionRequest.Type.GO_LANG,
                chaincodePath, metadataSourcePath);
        //org1 peer 节点的集合
        Collection<Peer> peersOrgx = new LinkedList<>();
        // 获取加入同一个通道的所有peer，根据org区分开
        for (Peer peer : org.getChannel().get().getPeers()) {
            if (peer.getUrl().contains(org.getOrgName())) {
                peersOrgx.add(peer);
              //  System.out.println(" lifecycleInstallChaincode 79 -----" + peer.getUrl());
            }
        }
        packageID = lifecycleInstallChaincode(org.getClient(), peersOrgx, lifecycleChaincodePackage);
        return packageID;
    }

    public String install(Map<String ,IntermediateOrg> orgs) throws ProposalException, InvalidArgumentException, IOException {
        Path metadataSourcePath = null;
        if (metadadataSource != null) {
            metadataSourcePath = Paths.get(metadadataSource);
        }
        LifecycleChaincodePackage lifecycleChaincodePackage = LifecycleChaincodePackage.fromSource(chaincodeLabel, Paths.get(chaincodeSourceLocation),
                TransactionRequest.Type.GO_LANG,
                chaincodePath, metadataSourcePath);
        for(IntermediateOrg org : orgs.values()){
            //org1 peer 节点的集合
            Collection<Peer> peersOrgx = new LinkedList<>();
            for (Peer peer : org.getChannel().get().getPeers()) {
            if (peer.getUrl().contains(org.getOrgName())) {
                peersOrgx.add(peer);
            }
            }
            packageID = lifecycleInstallChaincode(org.getClient(), peersOrgx, lifecycleChaincodePackage);
        }
        return packageID;
    }

    /**
     * 审批链码
     */
    public boolean approveformyorg(IntermediateOrg org) throws ProposalException, InvalidArgumentException, InterruptedException, ExecutionException, TimeoutException {
        BlockEvent.TransactionEvent transactionEvent = lifecycleApproveChaincodeDefinitionForMyOrg(org)
                .get(20000, TimeUnit.SECONDS);
        return transactionEvent.isValid();
    }

    public boolean approveformyorg(Map<String ,IntermediateOrg> orgs) throws Exception {

        try {
            for (IntermediateOrg org : orgs.values()){
                LifecycleApproveChaincodeDefinitionForMyOrgRequest
                        lifecycleApproveChaincodeDefinitionForMyOrgRequest = //  好长的类型
                        org.getClient().newLifecycleApproveChaincodeDefinitionForMyOrgRequest();
                lifecycleApproveChaincodeDefinitionForMyOrgRequest.setSequence(1);
                lifecycleApproveChaincodeDefinitionForMyOrgRequest.setChaincodeName(chaincodeName);
                lifecycleApproveChaincodeDefinitionForMyOrgRequest.setChaincodeVersion(chaincodeVersion);
                lifecycleApproveChaincodeDefinitionForMyOrgRequest.setInitRequired(true);
                if (null != chaincodeCollectionConfiguration) {
                    lifecycleApproveChaincodeDefinitionForMyOrgRequest.
                            setChaincodeCollectionConfiguration(chaincodeCollectionConfiguration);
                }
                if (null != chaincodeEndorsementPolicy) {
                    lifecycleApproveChaincodeDefinitionForMyOrgRequest.
                            setChaincodeEndorsementPolicy(chaincodeEndorsementPolicy);
                }
                lifecycleApproveChaincodeDefinitionForMyOrgRequest.setPackageId(packageID);

                //org1 peer 节点的集合
                Collection<Peer> peersOrgx = new LinkedList<>();
                // 获取加入同一个通道的所有peer，根据org区分开
                for (Peer peer : org.getChannel().get().getPeers()) {
                    if (peer.getUrl().contains(org.getOrgName())) {
                        peersOrgx.add(peer);
                    }
                }
                Collection<LifecycleApproveChaincodeDefinitionForMyOrgProposalResponse>
                        lifecycleApproveChaincodeDefinitionForMyOrgProposalResponse =
                        org.getChannel().get().sendLifecycleApproveChaincodeDefinitionForMyOrgProposal(
                                lifecycleApproveChaincodeDefinitionForMyOrgRequest, peersOrgx);
                org.getChannel().get().sendTransaction(lifecycleApproveChaincodeDefinitionForMyOrgProposalResponse);
            }
            return true;
        }catch (Exception e){
            throw new Exception(e);
        }


//        BlockEvent.TransactionEvent transactionEvent = lifecycleApproveChaincodeDefinitionForMyOrg(org)
//                .get(20000, TimeUnit.SECONDS);
//        return transactionEvent.isValid();
    }

    /**
     * 提交链码
     */
    public void commit(IntermediateOrg org) throws InvalidArgumentException, InterruptedException, ExecutionException, TimeoutException, ProposalException {
        commitChaincodeDefinitionRequest(org);
    }

    /**
     *  2.2.1的链码默认不会初始化，我们在这里手动执行
     *  默认执行 init
     */

    public void initChaincode(IntermediateOrg org ) throws ProposalException, InvalidArgumentException {

        TransactionProposalRequest transactionProposalRequest = org.getClient().newTransactionProposalRequest();
        transactionProposalRequest.setChaincodeName(chaincodeName);
        transactionProposalRequest.setChaincodeLanguage( TransactionRequest.Type.GO_LANG);
        transactionProposalRequest.setUserContext(org.getUser(org.getUsername()));
        transactionProposalRequest.setFcn("initLedger");
        transactionProposalRequest.setProposalWaitTime(20000);
        transactionProposalRequest.setArgs("");
        transactionProposalRequest.setInit(true);

        //org1 peer 节点的集合
        Collection<Peer> peersOrgx = new LinkedList<>();
        // 获取加入同一个通道的所有peer，根据org区分开,只要一个
        for (Peer peer : org.getChannel().get().getPeers()) {
            if (peer.getUrl().contains(org.getOrgName())) {
                peersOrgx.add(peer);
                break;
            }
        }
        Collection<ProposalResponse> transactionPropResp = org.getChannel().get().sendTransactionProposal(transactionProposalRequest,peersOrgx);
        Collection<ProposalResponse> successful = new LinkedList<>();
        for (ProposalResponse response : transactionPropResp) {
            if (response.getStatus() == ProposalResponse.Status.SUCCESS) {
                successful.add(response);
            }
        }
        org.getChannel().get().sendTransaction(successful);
    }


   private void commitChaincodeDefinitionRequest(IntermediateOrg org) throws InvalidArgumentException, ProposalException {

       LifecycleCommitChaincodeDefinitionRequest
       lifecycleCommitChaincodeDefinitionRequest = org.getClient().newLifecycleCommitChaincodeDefinitionRequest();
       lifecycleCommitChaincodeDefinitionRequest.setSequence(1);
       lifecycleCommitChaincodeDefinitionRequest.setChaincodeName(chaincodeName);
       lifecycleCommitChaincodeDefinitionRequest.setChaincodeVersion(chaincodeVersion);
       lifecycleCommitChaincodeDefinitionRequest.setInitRequired(true);
       if (null != chaincodeEndorsementPolicy) {
           lifecycleCommitChaincodeDefinitionRequest.setChaincodeEndorsementPolicy(chaincodeEndorsementPolicy);
       }
       if (null != chaincodeCollectionConfiguration) {
           lifecycleCommitChaincodeDefinitionRequest.setChaincodeCollectionConfiguration(chaincodeCollectionConfiguration);
       }
       lifecycleCommitChaincodeDefinitionRequest.setInitRequired(true);

       //org1 peer 节点的集合
       Collection<Peer> peersOrgx = new LinkedList<>();
       // 获取加入同一个通道的所有peer，根据org区分开
       for (Peer peer : org.getChannel().get().getPeers()) {
           if (peer.getUrl().contains(org.getOrgName())) {
               peersOrgx.add(peer);
           }
       }
       Collection<LifecycleCommitChaincodeDefinitionProposalResponse>
               lifecycleCommitChaincodeDefinitionProposalResponses =
               org.getChannel().get().sendLifecycleCommitChaincodeDefinitionProposal(
                       lifecycleCommitChaincodeDefinitionRequest,
               peersOrgx);
       try {
           org.getChannel().get().sendTransaction(lifecycleCommitChaincodeDefinitionProposalResponses).get(32000, TimeUnit.SECONDS);

       }catch (Exception e){
           System.out.println("Lifecy cleCommit >>>> "  + e.getMessage());
       }

    }


    private CompletableFuture<BlockEvent.TransactionEvent> lifecycleApproveChaincodeDefinitionForMyOrg(IntermediateOrg org)
            throws InvalidArgumentException, ProposalException {
        LifecycleApproveChaincodeDefinitionForMyOrgRequest
                lifecycleApproveChaincodeDefinitionForMyOrgRequest = //  好长的类型
                org.getClient().newLifecycleApproveChaincodeDefinitionForMyOrgRequest();
        lifecycleApproveChaincodeDefinitionForMyOrgRequest.setSequence(1);
        lifecycleApproveChaincodeDefinitionForMyOrgRequest.setChaincodeName(chaincodeName);
        lifecycleApproveChaincodeDefinitionForMyOrgRequest.setChaincodeVersion(chaincodeVersion);
        lifecycleApproveChaincodeDefinitionForMyOrgRequest.setInitRequired(true);
        if (null != chaincodeCollectionConfiguration) {
            lifecycleApproveChaincodeDefinitionForMyOrgRequest.
                    setChaincodeCollectionConfiguration(chaincodeCollectionConfiguration);
        }
        if (null != chaincodeEndorsementPolicy) {
            lifecycleApproveChaincodeDefinitionForMyOrgRequest.
                    setChaincodeEndorsementPolicy(chaincodeEndorsementPolicy);
        }
        lifecycleApproveChaincodeDefinitionForMyOrgRequest.setPackageId(packageID);

        //org1 peer 节点的集合
        Collection<Peer> peersOrgx = new LinkedList<>();
        // 获取加入同一个通道的所有peer，根据org区分开
        for (Peer peer : org.getChannel().get().getPeers()) {
            if (peer.getUrl().contains(org.getOrgName())) {
                peersOrgx.add(peer);
            }
        }
        Collection<LifecycleApproveChaincodeDefinitionForMyOrgProposalResponse>
                lifecycleApproveChaincodeDefinitionForMyOrgProposalResponse =
                org.getChannel().get().sendLifecycleApproveChaincodeDefinitionForMyOrgProposal(
                        lifecycleApproveChaincodeDefinitionForMyOrgRequest, peersOrgx);
        return org.getChannel().get().sendTransaction(lifecycleApproveChaincodeDefinitionForMyOrgProposalResponse);
    }

    private String lifecycleInstallChaincode(HFClient client, Collection<Peer> peers, LifecycleChaincodePackage lifecycleChaincodePackage) throws InvalidArgumentException, ProposalException {

        LifecycleInstallChaincodeRequest installProposalRequest = client.newLifecycleInstallChaincodeRequest();
        installProposalRequest.setLifecycleChaincodePackage(lifecycleChaincodePackage);
        installProposalRequest.setProposalWaitTime(200000);
        Collection<LifecycleInstallChaincodeProposalResponse> responses = client.sendLifecycleInstallChaincodeRequest(installProposalRequest, peers);
        String packageID = null;
        for (LifecycleInstallChaincodeProposalResponse response : responses) {
            if (response.getStatus() == ProposalResponse.Status.SUCCESS) {
                if (packageID == null) {
                    packageID = response.getPackageId();
                }
            }
        }
        return packageID;
    }


}
